﻿using CSharp.Libs.Database;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;

namespace CSharp.Libs.Media
{
    #region event handlers
    public delegate void FileObjectAvailableEventHandler(object sender, FileObjectAvailableEventArgs e);
    public class FileObjectAvailableEventArgs : EventArgs
    {
        public FileObject CreatedFileObject { get; set; }
    }
    #endregion



    #region parameter declarations
    #endregion



    public class FileTagger : IDisposable
    {
        #region declarations
        #region event handling
        public event FileObjectAvailableEventHandler FileObjectAvailable;
        protected void OnFileObjectAvailable(
            FileObjectAvailableEventArgs ea)
        {
            if (FileObjectAvailable != null)
            {
                FileObjectAvailable(this, ea);
            }
        }
        #endregion
        #endregion



        #region constructor
        public FileTagger()
        {
        }

        #region dispose pattern (http://www.codeproject.com/Articles/15360/Implementing-IDisposable-and-the-Dispose-Pattern-P)
        // some fields that require cleanup
        private bool disposed = false; // to detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    // clean up managed handles here
                    if (this.Storage != null)
                    {
                        this.Storage.Dispose();
                        this.Storage = null;
                    }
                }

                disposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }
        #endregion
        #endregion



        #region private functions
        private FileObject _getFileObjectForFile(
            string FullFileName)
        {
            if (!File.Exists(FullFileName))
            {
                throw new ArgumentException("File not found", "FileTagger.FullFileName");
            }

            //prepare FileObject
            FileObject fo = new FileObject();
            fo.FullFileName = FullFileName;

            //get Hash
            using (FileHashCalculator fhc = new FileHashCalculator())
            {
                fhc.FullFileName = FullFileName;
                fhc.CalculateFileHash();
                fo.Hash = fhc.CalculatedHash;
            }

            return fo;
        }
        private void _getFileObjectForFileAsync(
            object FullFileName)
        {
            //check parameter
            string strFullFileName = FullFileName.ToString();
            if (string.IsNullOrEmpty(strFullFileName))
            {
                throw new ArgumentException("Argument(string) is null or empty", "FullFileName");
            }

            //get FileObject
            FileObject fo = _getFileObjectForFile(strFullFileName);

            //throw event
            OnFileObjectAvailable(new FileObjectAvailableEventArgs() { CreatedFileObject = fo });
        }

        private void _getTagsForFileObject(
            FileObject fo)
        {
            if (string.IsNullOrEmpty(fo.Hash))
            {
                throw new ArgumentException("Hash is missing", "FileObject.Hash");
            }
            if (this.Storage == null)
            {
                throw new ArgumentNullException("No Storage (DataAccessLayer) defined", "FileTagger.Storage");
            }

            this.Storage.GetTagsForFileObject(fo);
        }

        private void _addTagToFileObject(
            FileObject fo,
            TagObject to)
        {
            this.Storage.AddTagToFileObject(fo, to);
        }

        private void _removeTagFromFileObject(
            FileObject fo,
            TagObject to)
        {
            this.Storage.RemoveTagFromFileObject(fo, to);
        }
        #endregion



        #region properties
        public DataAccessLayer Storage { get; set; }
        #endregion



        #region methods
        public FileObject GetFileObjectForFile(
            string FullFileName)
        {
            return _getFileObjectForFile(FullFileName);
        }
        public void GetFileObjectForFileAsync(
            string FullFileName)
        {
            Thread thrCreateFileObject = new Thread(_getFileObjectForFileAsync);
            thrCreateFileObject.Start(FullFileName);
        }

        public void GetTagsForFileObject(
            FileObject fo)
        {
            _getTagsForFileObject(fo);
        }
        //public void GetTagsForFileObjectAsync()
        //{
        //    Thread thrGetFileObjectTags = new Thread(_getTagsForFileObject);
        //    thrGetFileObjectTags.Start();
        //}

        public void AddTagToFileObject(
            FileObject fo,
            TagObject to)
        {
            _addTagToFileObject(fo, to);
        }

        public void RemoveTagFromFileObject(
            FileObject fo,
            TagObject to)
        {
            _removeTagFromFileObject(fo, to);
        }
        #endregion
    }
}
